// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
﻿package {
	// The ImageUploadListener handles events fired by the upload process (onCancel,
	// onOpen, onSecurityError, onIOError, onHTTPError, onComplete). It cooks them
	// into a unified form and passes them back to caller-specified progress and done
	// functions.
	//
	// ImageDocument and WebCamInBridge are the only users of the ImageUploadListener class.
	
	import flash.events.*;
	import imagine.ImageDocument;
	
	public class ImageUploadListener {
		private var _fnProgress:Function;
		private var _fnDone:Function;
		private var _obFrOrUrll:Object;
		private var _nHttpStatus:int = 0;

		// fr can be either a FileReference or a URLLoader instance
		// 	
		// Callback signatures:
		//   fnProgress(cbUploaded:Number, cbTotal:Number): void
		//   fnDone(err:Number, strError:String): void
		//   fnOpen?
		public function ImageUploadListener(obFrOrUrll:Object, fnProgress:Function, fnDone:Function) {
			_fnProgress = fnProgress;
			_fnDone = fnDone;
			_obFrOrUrll = obFrOrUrll; // Hang on to this so it doesn't get GC'ed while its I/O is pending
			
			obFrOrUrll.addEventListener(Event.CANCEL, OnCancel);
			obFrOrUrll.addEventListener(Event.COMPLETE, OnComplete);
			obFrOrUrll.addEventListener(IOErrorEvent.IO_ERROR, OnIOError);
			obFrOrUrll.addEventListener(ProgressEvent.PROGRESS, OnProgress);
			obFrOrUrll.addEventListener(SecurityErrorEvent.SECURITY_ERROR, OnSecurityError);
			obFrOrUrll.addEventListener(HTTPStatusEvent.HTTP_STATUS, OnHTTPStatus);
		}
		
		public function Dispose(): void {
			_obFrOrUrll.removeEventListener(Event.CANCEL, OnCancel);
			_obFrOrUrll.removeEventListener(Event.COMPLETE, OnComplete);
			_obFrOrUrll.removeEventListener(IOErrorEvent.IO_ERROR, OnIOError);
			_obFrOrUrll.removeEventListener(ProgressEvent.PROGRESS, OnProgress);
			_obFrOrUrll.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, OnSecurityError);
			_obFrOrUrll.removeEventListener(HTTPStatusEvent.HTTP_STATUS, OnHTTPStatus);
			_obFrOrUrll = null;
			_fnProgress = null;
			_fnDone = null;
		}
		
		private function OnCancel(evt:Event): void {
		}
		
		private function OnProgress(evt:ProgressEvent): void {
			_fnProgress(evt.bytesLoaded, evt.bytesTotal);
		}
		
		private function OnSecurityError(evt:SecurityErrorEvent): void {
			_fnDone(ImageDocument.errBaseImageUploadFailed, evt.text);
			Dispose();
		}
		
		// We hit this error under the following circumstances:
		// - the server is not running
		// - the server cannot process the uploaded image (too big, unsupported format)
		private function OnIOError(evt:IOErrorEvent): void {
			if (_nHttpStatus == 415)
				_fnDone(ImageDocument.errUnsupportedFileFormat, "I/O error: " + evt.text);
			else
				_fnDone(ImageDocument.errBaseImageUploadFailed, "I/O error: " + evt.text);
			Dispose();
		}
	
		// The most recent docs say:
		// [...] and a value of 0 is always generated by the Flash Player plug-in when
		// it is run in the following browsers, which do not pass HTTP status codes to
		// the player: Netscape, Mozilla, Safari, Opera, and Internet Explorer for the
		// Macintosh.
		//
		// HOWEVER, tests under Chrome 7, FF 3.6 & 4, IE 9, Safari 4 all fired
		// HTTPStatusEvents with the expected status codes.
		private function OnHTTPStatus(evt:HTTPStatusEvent): void {
			_nHttpStatus = evt.status;
			if (evt.status == 200 || evt.status == 0)
				return;
				
			// As far as I can tell, in every case that we encounter an HTTPStatusEvent we also
			// get an IOErrorEvent.IO_ERROR and/or an Event.COMPLETE. Therefore, it's best not to
			// fnDone/Dispose here because that will remove the handlers for the later events.
			// In particular, the IOErrorEvent won't be handled and the debug Flash Player
			// complains about that.
//			_fnDone(ImageDocument.errBaseImageUploadFailed, "HTTP error " + evt.status);
//			Dispose();
		}
	
		private function OnComplete(evt:Event): void {
			_fnDone(ImageDocument.errNone, "no error");
			Dispose();
		}
	}
}
